#include <brpc/server.h>
#include <butil/logging.h>
#include <map>
//实现语音识别子服务
#include "data_es.hpp"
#include "mysql_chat_session.hpp"
#include "mysql_chat_session_member.hpp"
#include "mysql_relation.hpp"
#include "mysql_friend_apply.hpp"

#include "utils.hpp"
#include "etcd.hpp"     //服务注册
#include "logger.hpp"   //日志模块
#include "channel.hpp"


#include "friend.pb.h"
#include "user.pb.h"
#include "base.pb.h"
#include "message.pb.h"


namespace xchat{
//proto rpc SpeechService ; package xchat
class FriendServiceImpl : public xchat::FriendService
{
public:
    FriendServiceImpl(const std::shared_ptr<elasticlient::Client> &es_client
                    ,const std::shared_ptr<odb::core::database> &mysql_client
                    ,const ServiceManager::ptr &channel_manager
                    ,const std::string &user_service_name
                    ,const std::string &message_service_name)
                    : _es_user(std::make_shared<ESUser>(es_client))
                    ,_mysql_chat_session(std::make_shared<ChatSessionTable>(mysql_client))
                    ,_mysql_chat_session_member(std::make_shared<ChatSessionMemberTable>(mysql_client))
                    ,_mysql_relation(std::make_shared<RelationTable>(mysql_client))
                    ,_mysql_apply(std::make_shared<FriendApplyTable>(mysql_client))
                    ,_user_service_name(user_service_name)
                    ,_message_service_name(message_service_name)
                    ,_mm_channels(channel_manager)
    {
    }
    //获取好友列表
    void GetFriendList(::google::protobuf::RpcController* controller,
                 const ::xchat::GetFriendListReq* request,
                 ::xchat::GetFriendListRsp* response,
                 ::google::protobuf::Closure* done)
    {
        brpc::ClosureGuard rpc_guard(done);
        auto error_response = [this, response](const std::string &rid, const std::string &error_msg) -> void
        {
            response->set_request_id(rid);
            response->set_success(false);
            response->set_errmsg(error_msg);
        };  
        //1.提取关键要素 用户ID
        std::string rid = request->request_id();
        std::string uid = request->user_id();
        //2.从数据库查询用户好友ID
        auto friends_id_list = _mysql_relation->friends(uid);
        std::unordered_set<std::string> user_id_lists;
        for (auto &id : friends_id_list) 
        {
            user_id_lists.insert(id);
        }   
        //3.用户子服务批量查询
        std::unordered_map<std::string, UserInfo> user_list;
        bool ret = GetUserInfo(rid, user_id_lists, user_list);
        if (ret == false) 
        {
            LOG_ERROR("{} - 批量获取用户信息失败!", rid);
            return error_response(rid, "批量获取用户信息失败!");
        }
        //4.返回结果
        for(const auto &user : user_list)
        {
            auto user_info = response->add_friend_list();
            user_info->CopyFrom(user.second);
        }
        response->set_request_id(rid);
        response->set_success(true);

    }
    //删除好友
    void FriendRemove(::google::protobuf::RpcController* controller,
                 const ::xchat::FriendRemoveReq* request,
                 ::xchat::FriendRemoveRsp* response,
                 ::google::protobuf::Closure* done)
    {
        brpc::ClosureGuard rpc_guard(done);
        auto error_response = [this, response](const std::string &rid, const std::string &error_msg) -> void
        {
            response->set_request_id(rid);
            response->set_success(false);
            response->set_errmsg(error_msg);
        };  
        //1.提取关键要素 用户ID 好友ID
        std::string rid = request->request_id();
        std::string uid = request->user_id();
        std::string friend_id = request->peer_id();
        //2.好友关系表删除好友关系
        bool ret = _mysql_relation->remove(uid, friend_id);
        if(!ret)
        {
            LOG_ERROR("{}-{}删除好友关系失败", uid, friend_id);
            return error_response(rid, "删除好友关系失败");
        }
        //3.从会话信息表中 删除对应会话(单聊)[内部还会删除会话成员表中的信息]
        ret = _mysql_chat_session->remove(uid, friend_id);
        if(!ret)
        {
            LOG_ERROR("{}-{}删除好友会话失败", uid, friend_id);
            return error_response(rid, "删除好友会话失败");
        }
        //3.组织响应
        response->set_request_id(rid);
        response->set_success(true);
    }
    //添加好友--发送好友申请             
    void FriendAdd(::google::protobuf::RpcController* controller,
                 const ::xchat::FriendAddReq* request,
                 ::xchat::FriendAddRsp* response,
               ::google::protobuf::Closure* done)
    {
        brpc::ClosureGuard rpc_guard(done);
        auto error_response = [this, response](const std::string &rid, const std::string &error_msg) -> void
        {
            response->set_request_id(rid);
            response->set_success(false);
            response->set_errmsg(error_msg);
        };  
        //1.提取关键信息 申请人ID 被申请人ID
        std::string rid = request->request_id();
        std::string uid = request->user_id();
        std::string respondent_id = request->respondent_id();
        //1.5 判断是不是已经好友 和 判断是不是已经申请过
        bool ret = _mysql_relation->exists(uid, respondent_id);
        if(ret)
        {
            LOG_ERROR("{}-{}已经是好友", uid, respondent_id);
            return error_response(rid, "已经是好友");
        }
        ret = _mysql_apply->exists(uid, respondent_id);
        if(ret)
        {
            LOG_ERROR("{}->{}已经申请过", uid, respondent_id);
            return error_response(rid, "重复好友申请");
        }
        //2.数据库申请
        std::string eid = uuid();
        FriendApply alppy(eid, uid, respondent_id);
        ret = _mysql_apply->insert(alppy);
        if(!ret)
        {
            LOG_ERROR("{}->{}申请好友失败", uid, respondent_id);
            return error_response(rid, "申请好友失败");
        }
        //3.组织响应
        response->set_request_id(rid);
        response->set_success(true);
        response->set_notify_event_id(eid);
    }
    //好友申请的处理  + 单聊会话创建
    void FriendAddProcess(::google::protobuf::RpcController* controller,
                 const ::xchat::FriendAddProcessReq* request,
                 ::xchat::FriendAddProcessRsp* response,
                 ::google::protobuf::Closure* done)
    {
        brpc::ClosureGuard rpc_guard(done);
        auto error_response = [this, response](const std::string &rid, const std::string &error_msg) -> void
        {
            response->set_request_id(rid);
            response->set_success(false);
            response->set_errmsg(error_msg);
        };  
        //1. 提取关键要素 申请人ID 被申请人ID 处理结果 事件ID
        std::string rid = request->request_id();
        std::string eid = request->notify_event_id();
        std::string uid = request->apply_user_id();//申请人
        std::string respondent_id = request->user_id(); //被申请人
        //2. 判断有没有申请事件  有就删除
        bool ret = _mysql_apply->exists(uid, respondent_id);
        if(!ret)
        {
            LOG_ERROR("{}->{}没有申请事件", uid, respondent_id);
            return error_response(rid, "没有申请事件");
        }
        ret = _mysql_apply->remove(uid, respondent_id);
        if(!ret)
        {
            LOG_ERROR("{}->{}删除申请事件失败", uid, respondent_id);
            return error_response(rid, "删除申请事件失败");
        }
        std::string cssid;
        //3. 如果处理结果是同意：向数据库新增好友关系信息；新增单聊会话信息及会话成员
        if(request->agree())
        {
            ret = _mysql_relation->insert(uid, respondent_id);
            if(!ret)
            {
                LOG_ERROR("{}<->{}添加好友关系失败", uid, respondent_id);
                return error_response(rid, "添加好友关系失败");
            }
            cssid = uuid();
            ChatSession css(cssid, "", ChatSessionType::SINGLE);
            ret = _mysql_chat_session->insert(css);
            if(!ret)
            {
                LOG_ERROR("{}<->{}新增单聊会话信息失败", uid, respondent_id);
                return error_response(rid, "新增单聊会话信息");
            }
            ChatSessionMember csm1(cssid, uid);
            ChatSessionMember csm2(cssid, respondent_id);
            std::vector<ChatSessionMember> mlist = {csm1, csm2};
            ret = _mysql_chat_session_member->append(mlist);
            if(!ret)
            {
                LOG_ERROR("{}<->{}新增单聊会话成员失败", uid, respondent_id);
                return error_response(rid, "新增单聊会话成员失败");
            }
        }
        //4. 组织响应
        response->set_request_id(rid);
        response->set_success(true);
        response->set_new_session_id(cssid);

    }                 
    //用户搜索 -->去加好友
    void FriendSearch(::google::protobuf::RpcController* controller,
                 const ::xchat::FriendSearchReq* request,
                 ::xchat::FriendSearchRsp* response,
                 ::google::protobuf::Closure* done)
    {
        brpc::ClosureGuard rpc_guard(done);
        auto error_response = [this, response](const std::string &rid, const std::string &error_msg) -> void
        {
            response->set_request_id(rid);
            response->set_success(false);
            response->set_errmsg(error_msg);
        };  
        //1. 提取请求中的关键要素：搜索关键字（可能是用户ID，可能是手机号，可能是昵称的一部分）
        std::string rid = request->request_id();
        std::string uid = request->user_id();
        std::string skey = request->search_key();
        //2. 根据用户ID，获取用户的好友ID列表
        auto friend_id_lists = _mysql_relation->friends(uid);
        friend_id_lists.push_back(uid);
        //3. 从ES搜索引擎进行用户信息搜索 --- 过滤掉当前的好友
        std::unordered_set<std::string> user_id_lists;
        auto res = _es_user->search(skey, friend_id_lists); //排除掉uid_list中的用户
        for(auto &user : res)
        {
            user_id_lists.insert(user.user_id()); //关键字搜索 比如文字消息搜索 可能重复 一个人发多个同样消息
        }
        //4. 根据获取到的用户ID， 从用户子服务器进行批量用户信息获取
        std::unordered_map<std::string, UserInfo> user_list;
        bool ret = GetUserInfo(rid, user_id_lists, user_list);
        if (ret == false) 
        {
            LOG_ERROR("{} - 批量获取用户信息失败!", rid);
            return error_response(rid, "批量获取用户信息失败!");
        }
        //5. 组织响应
        for(const auto &user : user_list)
        {
            auto user_info = response->add_user_info();
            user_info->CopyFrom(user.second);
        }
        response->set_request_id(rid);
        response->set_success(true);
    }          
    //获取待处理的，申请自己好友的信息列表                 
    void GetPendingFriendEventList(::google::protobuf::RpcController* controller,
                 const ::xchat::GetPendingFriendEventListReq* request,
                 ::xchat::GetPendingFriendEventListRsp* response,
                 ::google::protobuf::Closure* done)
    {
        brpc::ClosureGuard rpc_guard(done);
        auto error_response = [this, response](const std::string &rid, const std::string &error_msg) -> void
        {
            response->set_request_id(rid);
            response->set_success(false);
            response->set_errmsg(error_msg);
        };  
        //1. 提取关键要素：当前用户ID
        std::string rid = request->request_id();
        std::string uid = request->user_id();
        //2. 从数据库获取待处理的申请事件信息 --- 申请人用户ID列表
        auto res = _mysql_apply->apply_users(uid);
        std::unordered_set<std::string> user_id_lists;
        for (auto &id : res) {
            user_id_lists.insert(id);
        }
        //3. 批量获取申请人用户信息、
        std::unordered_map<std::string, UserInfo> user_list;
        bool ret = GetUserInfo(rid, user_id_lists, user_list);
        if (ret == false) {
            LOG_ERROR("{} - 批量获取用户信息失败!", rid);
            return error_response(rid, "批量获取用户信息失败!");
        }
        //4. 组织响应
        response->set_request_id(rid);
        response->set_success(true);
        for (const auto & user_it : user_list) {
            auto ev = response->add_event();
            ev->mutable_sender()->CopyFrom(user_it.second);
        }
    }     
    //会话列表获取
    void GetChatSessionList(::google::protobuf::RpcController* controller,
                 const ::xchat::GetChatSessionListReq* request,
                 ::xchat::GetChatSessionListRsp* response,
                 ::google::protobuf::Closure* done)
    {
        brpc::ClosureGuard rpc_guard(done);
        auto error_response = [this, response](const std::string &rid, const std::string &error_msg) -> void
        {
            response->set_request_id(rid);
            response->set_success(false);
            response->set_errmsg(error_msg);
        };  
        //获取聊天会话的作用：一个用户登录成功后，能够展示自己的历史聊天信息
        //1. 提取请求中的关键要素：当前请求用户ID
        std::string rid = request->request_id();
        std::string uid = request->user_id();
        //2. 从数据库中查询出用户的单聊会话列表 取出所有的好友ID，从用户子服务获取用户信息
        auto sf_list = _mysql_chat_session->singleChatSession(uid);

        std::unordered_set<std::string> users_id_list;
        for (const auto &f : sf_list) 
        {
            users_id_list.insert(f._friend_id);
        }
        std::unordered_map<std::string, UserInfo> user_list;
        bool ret = GetUserInfo(rid, users_id_list, user_list);
        if (ret == false) {
            LOG_ERROR("{} - 批量获取用户信息失败！", rid);
            return error_response(rid, "批量获取用户信息失败!");
        }
        //3. 从数据库中查询出用户的群聊会话列表
        auto gc_list = _mysql_chat_session->groupChatSession(uid);
        //5. 组织响应 【单聊：会话名称就是好友名称；会话头像就是好友头像】【群聊 头像前端固定渲染】
        for (const auto &f : sf_list) {
            auto chat_session_info = response->add_chat_session_info_list();
            chat_session_info->set_single_chat_friend_id(f._friend_id);
            chat_session_info->set_chat_session_id(f._chat_session_id);
            chat_session_info->set_chat_session_name(user_list[f._friend_id].nickname());
            chat_session_info->set_avatar(user_list[f._friend_id].avatar());
            //从消息存储子服务获取会话最后一条消息
            MessageInfo msg;
            ret = GetRecentMsg(rid, f._chat_session_id, msg);
            if (ret == false) {continue;}
            chat_session_info->mutable_prev_message()->CopyFrom(msg);
        }
        for (const auto &f : gc_list) {
            auto chat_session_info = response->add_chat_session_info_list();
            chat_session_info->set_chat_session_id(f._chat_session_id);
            chat_session_info->set_chat_session_name(f._chat_session_name);
            //从消息存储子服务获取会话最后一条消息
            MessageInfo msg;
            ret = GetRecentMsg(rid, f._chat_session_id, msg);
            if (ret == false) { continue; }
            chat_session_info->mutable_prev_message()->CopyFrom(msg);
        }
        response->set_request_id(rid);
        response->set_success(true);
    }
    //创建群聊会话 FriendAddProcess中已经实现了创建单聊
    void ChatSessionCreate(::google::protobuf::RpcController* controller,
                 const ::xchat::ChatSessionCreateReq* request,
                 ::xchat::ChatSessionCreateRsp* response,
                 ::google::protobuf::Closure* done)
    {
        brpc::ClosureGuard rpc_guard(done);
        auto error_response = [this, response](const std::string &rid, const std::string &error_msg) -> void
        {
            response->set_request_id(rid);
            response->set_success(false);
            response->set_errmsg(error_msg);
        };  
            //创建会话，其实针对的是用户要创建一个群聊会话
            //1. 提取请求关键要素：会话名称，会话成员
            std::string rid = request->request_id();
            std::string uid = request->user_id();
            std::string cssname = request->chat_session_name();
            
            //2. 生成会话ID，向数据库添加会话信息，添加会话成员信息
            std::string cssid = uuid();
            ChatSession cs(cssid, cssname, ChatSessionType::GROUP);
            bool ret = _mysql_chat_session->insert(cs);
            if (ret == false) {
                LOG_ERROR("{} - 向数据库添加会话信息失败: {}", rid, cssname);
                return error_response(rid, "向数据库添加会话信息失败!");
            }
            std::vector<ChatSessionMember> member_list;
            for (int i = 0; i < request->member_id_list_size(); i++) {
                ChatSessionMember csm(cssid, request->member_id_list(i));
                member_list.push_back(csm);
            }
            ret = _mysql_chat_session_member->append(member_list);
            if (ret == false) {
                LOG_ERROR("{} - 向数据库添加会话成员信息失败: {}", rid, cssname);
                return error_response(rid, "向数据库添加会话成员信息失败!");
            }
            //3. 组织响应---组织会话信息
            response->set_request_id(rid);
            response->set_success(true);
            response->mutable_chat_session_info()->set_chat_session_id(cssid);
            response->mutable_chat_session_info()->set_chat_session_name(cssname);
            //新创建的群聊 没有最后一条消息
    } 
    //获取会话成员列表  用于用户查看群聊信息的时候
    void GetChatSessionMember(::google::protobuf::RpcController* controller,
                 const ::xchat::GetChatSessionMemberReq* request,
                 ::xchat::GetChatSessionMemberRsp* response,
                 ::google::protobuf::Closure* done)
    {
        brpc::ClosureGuard rpc_guard(done);
        auto error_response = [this, response](const std::string &rid, const std::string &error_msg) -> void
        {
            response->set_request_id(rid);
            response->set_success(false);
            response->set_errmsg(error_msg);
        };  
        //用于用户查看群聊成员信息的时候：进行成员信息展示
        //1. 提取关键要素：聊天会话ID
        std::string rid = request->request_id();
        std::string uid = request->user_id();
        std::string cssid = request->chat_session_id();
        //2. 从数据库获取会话成员ID列表
        auto member_id_lists = _mysql_chat_session_member->members(cssid);
        std::unordered_set<std::string> uid_list;
        for (const auto &id : member_id_lists) {
            uid_list.insert(id);
        }
        //3. 从用户子服务批量获取用户信息
        std::unordered_map<std::string, UserInfo> user_list;
        bool ret = GetUserInfo(rid, uid_list, user_list);
        if (ret == false) {
            LOG_ERROR("{} - 从用户子服务获取用户信息失败！", rid);
            return error_response(rid, "从用户子服务获取用户信息失败!");
        }
        //4. 组织响应
        response->set_request_id(rid);
        response->set_success(true);
        for (const auto &uit : user_list) {
            auto user_info = response->add_member_info_list();
            user_info->CopyFrom(uit.second);
        }
    }              
    ~FriendServiceImpl(){}
private:
    //拿到历史最近一条消息MessageInfo 用于上级组装->>ChatSessionInfo
    bool GetRecentMsg(const std::string &rid, 
            const std::string &cssid, MessageInfo &msg)
    {
        auto channel = _mm_channels->choose(_message_service_name);
        if (!channel) 
        {
            LOG_ERROR("{} - 获取消息存储子服务信道失败!!", rid);
            return false;
        }

        GetRecentMsgReq get_minfo_req;

        get_minfo_req.set_request_id(rid);
        get_minfo_req.set_chat_session_id(cssid);
        get_minfo_req.set_msg_count(1);
        xchat::MsgStorageService_Stub stub(channel.get());
        std::unique_ptr<xchat::GetRecentMsgRsp> get_minfo_rsp(new xchat::GetRecentMsgRsp());
        std::unique_ptr<brpc::Controller> cntl(new brpc::Controller());
        stub.GetRecentMsg(cntl.get(), &get_minfo_req, get_minfo_rsp.get(), nullptr); // 同步调用
        if (cntl->Failed() == true) 
        {
            LOG_ERROR("{} - 用户子服务调用失败: {}", rid, cntl->ErrorText());
            return false;
        }
        if (get_minfo_rsp->success() == false) 
        {
            LOG_ERROR("{} - 批量获取用户信息失败: {}", rid, get_minfo_rsp->errmsg());
            return false;
        }
        if (get_minfo_rsp->msg_list_size() > 0) 
        {
            //新创建的会话没有 有消息的就设置上
            msg.CopyFrom(get_minfo_rsp->msg_list(0));
            return true;
        }
        return true;
    }
    bool GetUserInfo(const std::string &rid, 
        const std::unordered_set<std::string> &uid_list,
        std::unordered_map<std::string, UserInfo> &user_list) 
    {
        auto channel = _mm_channels->choose(_user_service_name);
        if (!channel) 
        {
            LOG_ERROR("{} - 获取用户子服务信道失败！！", rid);
            return false;
        }

        GetMultiUserInfoReq get_uinfo_req;

        get_uinfo_req.set_request_id(rid);
        for (auto &id : uid_list)
        {
            get_uinfo_req.add_users_id(id);
        }
        xchat::UserService_Stub stub(channel.get());
        std::unique_ptr<xchat::GetMultiUserInfoRsp> get_uinfo_rsp(new xchat::GetMultiUserInfoRsp());
        std::unique_ptr<brpc::Controller> cntl(new brpc::Controller());
        stub.GetMultiUserInfo(cntl.get(), &get_uinfo_req, get_uinfo_rsp.get(), nullptr); // 同步调用
        if (cntl->Failed() == true) 
        {
            LOG_ERROR("{} - 用户子服务调用失败: {}", rid, cntl->ErrorText());
            return false;
        }
        if (get_uinfo_rsp->success() == false) 
        {
            LOG_ERROR("{} - 批量获取用户信息失败: {}", rid, get_uinfo_rsp->errmsg());
            return false;
        }
        for (const auto & user_it : get_uinfo_rsp->users_info()) 
        {
            user_list.insert(std::make_pair(user_it.first, user_it.second));
        }
        return true;
    }
private:
    //es客户端相关对象
    ESUser::ptr _es_user; 
    //mysql客户端相关对象
    FriendApplyTable::ptr _mysql_apply;
    ChatSessionTable::ptr _mysql_chat_session;
    ChatSessionMemberTable::ptr _mysql_chat_session_member;
    RelationTable::ptr _mysql_relation;
    //redis客户端相关对象
    //rpc调用客户端相关对象
    std::string _user_service_name;        
    std::string _message_service_name;        
    ServiceManager::ptr _mm_channels; //信道管理对象

};
class FriendServer
{
    public:
        using ptr = std::shared_ptr<FriendServer>;
        FriendServer(const Discovery::ptr &service_discovery, 
                const Registry::ptr &reg_client, 
                const std::shared_ptr<elasticlient::Client> &es_client, 
                const std::shared_ptr<odb::core::database> &mysql_client,
                const std::shared_ptr<brpc::Server> &server)
            :_es_client(es_client)
            ,_mysql_client(mysql_client)
            ,_service_discovery(service_discovery)
            ,_reg_client(reg_client)
            ,_rpc_server(server)
        {}
        ~FriendServer()
        {}

        //搭建rpc服务器 并启动服务器
        void start()
        {
            _rpc_server->RunUntilAskedToQuit();
        }
    private:
        std::shared_ptr<elasticlient::Client> _es_client; //es客户端
        std::shared_ptr<odb::core::database> _mysql_client; //数据库连接
        Discovery::ptr _service_discovery; //服务发现对象
        Registry::ptr _reg_client;  //注册中心
        std::shared_ptr<brpc::Server> _rpc_server;       //rpc服务
};
//建筑师模式
class FriendServerBuilder
{
    public:
        //构造es客户端对象
        void make_es_object(const std::vector<std::string>& host_list)
        {
            _es_client = ESClientFactory::createClient(host_list);
        }
        //构造mysql客户端对象
        void make_mysql_object(const std::string &user, const std::string &pwd, 
                        const std::string &host, const std::string &db,const std::string &cset,
                        int port, int conn_pool_count)
        {
            _mysql_client = ODBFactory::create(user, pwd, host, db, cset, port, conn_pool_count);
        }
        //用于构造服务发现客户端对象 & 信道管理对象
        void make_discovery_object(const std::string &reg_host, const std::string &base_service_name,
                                    const std::string &user_service_name, const std::string &message_service_name)
        {
            _user_service_name = user_service_name;
            _message_service_name = message_service_name;
            _mm_channels = std::make_shared<ServiceManager>();
            _mm_channels->declared(user_service_name);   //声明关心那些服务
            _mm_channels->declared(message_service_name);   //声明关心那些服务
            auto put_cb = std::bind(&ServiceManager::onServiceOnline, _mm_channels.get(), std::placeholders::_1, std::placeholders::_2);
            auto del_cb = std::bind(&ServiceManager::onServiceOffline, _mm_channels.get(), std::placeholders::_1, std::placeholders::_2);
            _service_discovery = std::make_shared<Discovery>(reg_host, base_service_name, put_cb, del_cb);
        }
        //用于构造服务注册客户端对象  服务中心地址 服务名称 当前实例的外部访问地址
        void make_registry_object(const std::string &reg_host, const std::string server_name, const std::string &access_host)
        {
            _reg_client = std::make_shared<Registry>(reg_host);
            _reg_client->registry(server_name, access_host);
        }
        void make_rpc_server(uint16_t port, uint32_t timeout, uint8_t num_threads)
        {
            if(!_es_client)
            {
                LOG_ERROR(" es客户端对象未构造!");
                abort();
            }
            if (!_mysql_client)
            {
                LOG_ERROR("mysql客户端对象未构造");
                abort();
            }
            if(!_mm_channels)
            {
                LOG_ERROR("信道管理对象未初始化");
                abort();
            }
            _rpc_server = std::make_shared<brpc::Server>();
            FriendServiceImpl *friend_service = new FriendServiceImpl(_es_client, _mysql_client
                , _mm_channels, _user_service_name, _message_service_name);
            int ret = _rpc_server->AddService(friend_service, brpc::ServiceOwnership::SERVER_OWNS_SERVICE);
            if(ret == -1)
            {
                LOG_ERROR("添加rpc服务失败!");
                abort();
            }
            brpc::ServerOptions options;
            options.idle_timeout_sec = timeout;  //连接空闲超时时间-超时后连接被关闭
            options.num_threads = num_threads;        //io线程数量
            //4.启动服务器
            ret = _rpc_server->Start(port, &options);
            if(ret == -1)
            {
                LOG_ERROR("启动rpc服务器失败!");
                abort();
            }
        }
        FriendServer::ptr build()
        {
            //_rpc_server 构造前 其余的得构造好

            if(!_service_discovery)
            {
                LOG_ERROR("服务发现对象未初始化");
                abort();
            }
            if(!_reg_client)
            {
                LOG_ERROR("服务发现对象未初始化");
                abort();
            }
            if(!_rpc_server)
            {
                LOG_ERROR("rpc服务对象未初始化");
                abort();
            }
           
            FriendServer::ptr server = std::make_shared<FriendServer>(_service_discovery, _reg_client, _es_client, 
                _mysql_client, _rpc_server);
            return server;
        }
    private:
        std::string _user_service_name;
        std::string _message_service_name;
        Discovery::ptr _service_discovery; //服务发现对象
        Registry::ptr _reg_client;  //注册中心
        std::shared_ptr<brpc::Server> _rpc_server;       //rpc服务
        std::shared_ptr<elasticlient::Client> _es_client; //es客户端
        std::shared_ptr<odb::core::database> _mysql_client; //数据库连接
        ServiceManager::ptr _mm_channels; //信道管理对象
};
}